package newx

import (
	"bytes"
	"encoding/base64"
	"fmt"
 	gmccompress "github.com/snail007/gmc/util/compress"
	"github.com/snail007/gmct/tool"
	"github.com/snail007/gmct/util"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

var (
	only = []string{".go"}
)

type NewxArgs struct {
	SubName   *string
	Web       WebArgs
	API       APIArgs
	SimpleAPI SimpleAPIArgs
	Admin     AdminArgs
}

type WebArgs struct {
	Package *string
}

type APIArgs struct {
	Package *string
}

type SimpleAPIArgs struct {
	Package *string
}

type AdminArgs struct {
	Package *string
}

func NewArgs() NewxArgs {
	return NewxArgs{
		SubName: new(string),
		Web: WebArgs{
			Package: new(string),
		},
		API: APIArgs{
			Package: new(string),
		},
		SimpleAPI: SimpleAPIArgs{
			Package: new(string),
		},
		Admin: AdminArgs{
			Package: new(string),
		},
	}
}

type Newx struct {
	tool.GMCTool
	GOPATH string
	dest   string
	cfg    NewxArgs
}

func NewX() *Newx {
	return &Newx{

	}
}

func (s *Newx) init(args0 interface{}) (err error) {

	s.cfg = args0.(NewxArgs)
	s.GOPATH = strings.TrimSpace(os.Getenv("GOPATH"))
	if s.GOPATH == "" {
		return fmt.Errorf("GOPATH environment variable not found")
	}
	// GOPATH may be contains multiple paths
	if filepath.Separator == '\\' {
		// windows
		s.GOPATH = strings.Split(s.GOPATH, ";")[0]
	} else {
		// linux
		s.GOPATH = strings.Split(s.GOPATH, ":")[0]
	}
	s.GOPATH = filepath.Join(s.GOPATH, "src")
	return
}

func (s *Newx) Start(args interface{}) (err error) {
	err = s.init(args)
	if err != nil {
		return
	}
	err = s.decompress()
	if err != nil {
		return
	}
	s.replace()
	fmt.Printf("initialized at: %s\n", s.dest)
	return
}

func (s *Newx) Stop() {

	return
}
func (s *Newx) replace() {
	var oldStr, newStr string
	switch *s.cfg.SubName {
	case "web":
		oldStr = "mygmcweb"
		newStr = *s.cfg.Web.Package
	case "api":
		oldStr = "mygmcapi"
		newStr = *s.cfg.API.Package
	case "api-simple":
		oldStr = "mygmcapi"
		newStr = *s.cfg.SimpleAPI.Package
	case "admin":
		oldStr = "mygmcadmin"
		newStr = *s.cfg.Admin.Package
	}
	filepath.Walk(s.dest, func(path string, info os.FileInfo, err error) error {
		ok := false
		for _, v := range only {
			if util.ExistsFile(path) &&
				(strings.HasSuffix(info.Name(), v) || v == info.Name()) {
				ok = true
				break
			}
		}
		if !ok {
			return nil
		}
		b, _ := ioutil.ReadFile(path)
		newFileStr := strings.Replace(string(b), oldStr, newStr, 1)
		ioutil.WriteFile(path, []byte(newFileStr), 0755)
		return nil
	})
	modTpl := fmt.Sprintf(`module %s

go 1.12
`, newStr)

	ioutil.WriteFile(filepath.Join(s.dest, "go.mod"), []byte(modTpl), 0755)
}
func (s *Newx) decompress() (err error) {
	data := ""
	s.dest = s.GOPATH
	switch *s.cfg.SubName {
	case "web":
		data = webData
		s.dest = filepath.Join(s.dest, *s.cfg.Web.Package)
	case "api":
		data = apiData
		s.dest = filepath.Join(s.dest, *s.cfg.API.Package)
	case "api-simple":
		data = simpleapiData
		s.dest = filepath.Join(s.dest, *s.cfg.SimpleAPI.Package)
	case "admin":
		data = adminData
		s.dest = filepath.Join(s.dest, *s.cfg.Admin.Package)
	}
	s.dest, _ = filepath.Abs(s.dest)

	if !util.Exists(s.dest) {
		err = os.MkdirAll(s.dest, 0755)
		if err != nil {
			return
		}
	} else if !util.IsEmptyDir(s.dest) {
		err = fmt.Errorf("%s directory is not empty.", s.dest)
		if err != nil {
			return
		}
	}

	d, err := base64.StdEncoding.DecodeString(data)
	if err != nil {
		return
	}
	var b bytes.Buffer
	b.Write(d)
	_, err = gmccompress.Unpack(&b, s.dest)
	return
}
